﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows.Forms;


namespace Marmat.Forms
{
    /// <summary>
    /// 表示 Windows 组合框控件。
    /// </summary>
    [Designer("Marmat.Forms.Design.ComboBoxDesigner")]
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(System.Windows.Forms.ComboBox))]
    public partial class ComboBox : DropDownBox
    {
        //private DevExpress.XtraEditors.Controls.EditorButton _deleteButton;

        /// <summary>
        /// 初始化 Marmat.Forms.ComboBox 类的新实例。
        /// </summary>
        public ComboBox()
        {

            // 此调用是设计器所必需的。
            this.InitializeComponent();

            // 在 InitializeComponent() 调用之后添加任何初始化。
            this.ShowModalButton = false;
            base.PopupControl = new ComboBoxPopupForm(this);
            //this._deleteButton = new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Delete);
            //this._deleteButton.Visible = false;
            //this._deleteButton.Click += deleteButton_Click;
            base.TextEditStyle = TextEditStyles.DisableTextEditor;
            this.m_BaseEdit.KeyDown += this.m_BaseEdit_KeyDown;
            this.ValueChanged += ComboBox_ValueChanged;
        }

        private void ComboBox_ValueChanged(object sender, EventArgs e)
        {
            //this.updateClearButton();
        }

        /// <summary>
        /// 获取该控件的下拉窗口
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        internal ComboBoxPopupForm Form
        {
            get => (ComboBoxPopupForm)base.PopupControl;
        }

        public override object DataSource
        {
            get => base.DataSource;
            set
            {
                base.DataSource = value;
                this.Form.listBoxControl1.DataSource = value;
            }
        }

        public override string DisplayMember
        {
            get => base.DisplayMember;
            set
            {
                base.DisplayMember = value;
                this.Form.listBoxControl1.DisplayMember = value;
            }
        }

        public override string ValueMember
        {
            get => base.ValueMember;
            set
            {
                base.ValueMember = value;
                this.Form.listBoxControl1.ValueMember = value;
            }
        }

        /// <summary>
        /// 返回或设置列表项目，不同项目之间用符号“|”隔开。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string ComboList
        {
            get => this._ComboList;
            set
            {
                if (!ReferenceEquals(this.ComboList, value))
                {
                    this.Items.Clear();
                    this._ComboList = value;
                    if (!string.IsNullOrEmpty(value))
                    {
                        var Items = value.Split('|');
                        foreach (string item in Items)
                            this.Items.Add(item);
                    }
                }
            }
        }

        private string _ComboList;

        protected override bool IsReadOnly
        {
            get => base.IsReadOnly;
            set
            {
                base.IsReadOnly = value;
                //this.updateClearButton();
            }
        }

        ///// <summary>
        ///// 获取或设置是否显示清除按钮。
        ///// </summary>
        //[DefaultValue(true)]
        //public bool ShowClearButton
        //{
        //    get => showClearButton;
        //    set
        //    {
        //        showClearButton = value;
        //        this.updateClearButton();
        //    }
        //}

        //private void updateClearButton()
        //{
        //    bool showClearButton = !this.IsReadOnly && this.ShowClearButton && !string.IsNullOrEmpty(this.BaseEdit.Text);
        //    if (showClearButton && !this.TextEdit1.Properties.Buttons.Contains(this._deleteButton))
        //        this.TextEdit1.Properties.Buttons.Add(this._deleteButton);
        //    else if (!showClearButton && this.TextEdit1.Properties.Buttons.Contains(this._deleteButton))
        //        this.TextEdit1.Properties.Buttons.Remove(this._deleteButton);
        //    this._deleteButton.Visible = showClearButton;
        //    this.comboButton.Visible = !this._deleteButton.Visible;
        //}

        /// <summary>
        /// 获取一个对象，该对象表示该  Marmat.Forms.ComboBox 中所包含项的集合。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Bindable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Category("数据")]
        [Description("获取一个对象，该对象表示该  Marmat.Forms.ComboBox 中所包含项的集合。")]
        public ItemCollection Items
        {
            get
            {
                if (this.m_Items is null)
                    this.m_Items = new ItemCollection(this.Form.listBoxControl1.Items);
                return this.m_Items;
            }
        }

        private ItemCollection m_Items;

        /// <summary>
        /// 获取或设置  Marmat.Forms.BComboBox 中是文本编辑风格。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(typeof(TextEditStyles), "DisableTextEditor")]
        public override TextEditStyles TextEditStyle
        {
            get => base.TextEditStyle;
            set => base.TextEditStyle = value;
        }

        /// <summary>
        /// 整数型，返回或设置所输入或选择的值，在列表项目中的位置。
        /// 如果没有输入或选择值，或者输入的值不包括在列表项目中，则返回-1。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DefaultValue(-1)]
        public int SelectedIndex
        {
            get => this.m_SelectedIndex;
            set
            {
                this.m_SelectedIndex = value;
                this.Form.listBoxControl1.SelectedIndex = value;
                this.Value = this.Form.listBoxControl1.SelectedValue;
                SelectedIndexChanged?.Invoke(this, EventArgs.Empty);
            }
        }

        private int m_SelectedIndex = -1;

        /// <summary>
        /// 触发自定义创建项的点击事件。
        /// </summary>
        internal void RaiseCustomCreateItemClick()
        {
            var arg = new ComboBoxCustomCreateItemEventArgs();
            CustomCreateItemClick?.Invoke(this, arg);
            if (arg.Value is object)
            {
                this.SelectedValue = arg.Value;
            }

            this.CloseDropDown();
        }

        /// <summary>
        /// 获取或设置  Marmat.Forms.BComboBox 中当前选定的项。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Browsable(false)]
        [DefaultValue(null)]
        public object SelectedItem
        {
            get => this.Form.listBoxControl1.SelectedItem;
        }

        /// <summary>
        /// 获取或设置  Marmat.Forms.BComboBox 中当前选定的项的值。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [DefaultValue(null)]
        public object SelectedValue
        {
            get => this._selectedValue;
            set
            {
                if (!ReferenceEquals(this._selectedValue, value) || !ReferenceEquals(this.Value, value))
                {
                    this._selectedValue = value;
                    this.Value = value;
                    SelectedValueChanged?.Invoke(this, EventArgs.Empty);
                }
            }
        }

        private object _selectedValue;

        [Browsable(false)]
        public new object Value
        {
            get => this.BaseEdit.EditValue;
            set
            {
                if (!ReferenceEquals(this.Value, value))
                {
                    BaseEdit.EditValue = value;
                    this.Form.listBoxControl1.SelectedValue = value;
                    this.m_SelectedIndex = this.Form.listBoxControl1.SelectedIndex;
                    this._selectedValue = value;
                }
            }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        internal new PopupControl PopupControl
        {
            get
            {
                if (base.PopupControl is null)
                    base.PopupControl = new ComboBoxPopupForm(this);
                return base.PopupControl;
            }
        }

        [DefaultValue(false)]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override bool ShowModalButton
        {
            get => base.ShowModalButton;
            set => base.ShowModalButton = value;
        }

        private bool _allowCreate;
        private bool showClearButton = true;

        /// <summary>
        /// 获取或设置组合框是否显示新增按钮。
        /// </summary>
        [DefaultValue(false)]
        [Category("行为")]
        [Description("获取或设置组合框是否显示新增按钮。")]
        public bool AllowCreate
        {
            get => this._allowCreate;
            set => this._allowCreate = value;
        }

        /// <summary>
        /// 获取或设置组合框中项的高度。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(20)]
        [Category("外观")]
        [Description("获取或设置组合框中项的高度。")]
        public int ItemHeight
        {
            get => ((ComboBoxPopupForm)base.PopupControl).listBoxControl1.ItemHeight;
            set => ((ComboBoxPopupForm)base.PopupControl).listBoxControl1.ItemHeight = value;
        }

        /// <summary>
        /// 获取包含在集合中的元素数量。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Browsable(false)]
        public int ItemCount
        {
            get => this.Form.listBoxControl1.ItemCount;
        }

        private void BComboBox_DropDownFormOpening(object sender, CancelEventArgs e)
        {
            if (base.PopupControl is object && base.PopupControl.IsDisposed == false)
            {
                ComboBoxPopupForm popupControl = (ComboBoxPopupForm)base.PopupControl;
                int index = 0;
                var selectedvalue = this.Value;
                for (int i = 0, loopTo = popupControl.listBoxControl1.ItemCount - 1; i <= loopTo; i++)
                {
                    var itemvalue = popupControl.listBoxControl1.GetItemValue(i);
                    if (itemvalue is object)
                    {
                        if (selectedvalue is object && itemvalue.Equals(selectedvalue))
                        {
                            index = i;
                            break;
                        }
                    }
                }

                popupControl.listBoxControl1.SetSelected(index, true);
                popupControl.Width = this.Width - this.BaseEdit.Left - 2;
                int count = Math.Max(1, popupControl.listBoxControl1.ItemCount);
                count = Math.Min(10, count);
                popupControl.Height = this.ItemHeight * (count + 1);
                popupControl.linkLabel1.Visible = this.AllowCreate;
                popupControl.linkLabel1.Height = this.ItemHeight;
            }
        }

        internal void BComboBox_CustomDisplayText(object sender, CustomDisplayTextEventArgs e)
        {
            if (e.Value is not null)
            {
                if (this.DataSource is not null)
                {
                    if (this.DataSource is DataTable dataTable && !string.IsNullOrEmpty(this.ValueMember))
                    {
                        foreach (DataRow dr in dataTable.Rows)
                        {
                            var item_value = dr[this.ValueMember];
                            if (Equals(item_value, e.Value) || this.EqualsValue(e.Value, item_value))
                            {
                                if (!string.IsNullOrEmpty(this.DisplayMember))
                                {
                                    e.DisplayText = dr[this.DisplayMember]?.ToString();
                                }
                                else
                                {
                                    e.DisplayText = item_value?.ToString();
                                }
                            }
                        }
                    }
                    else if (this.DataSource is IEnumerable items)
                    {
                        foreach (object item in items)
                        {
                            if (item is null)
                                continue;
                            object item_value = null;
                            object item_display = null;
                            var members = item.GetType().GetMembers();
                            var member = members.FirstOrDefault(x => (x.Name ?? "") == (this.ValueMember ?? "") && (x is FieldInfo || x is PropertyInfo));
                            if (member is object)
                            {
                                if (member is FieldInfo field)
                                    item_value = field.GetValue(item);
                                if (member is PropertyInfo property)
                                    item_value = property.GetValue(item);
                            }

                            if (Equals(e.Value, item_value))
                            {
                                if (!string.IsNullOrEmpty(this.DisplayMember))
                                {
                                    member = members.FirstOrDefault(x => (x.Name ?? "") == (this.DisplayMember ?? "") && (x is FieldInfo || x is PropertyInfo));
                                    if (member is object)
                                    {
                                        if (member is FieldInfo field)
                                            item_display = field.GetValue(item);
                                        if (member is PropertyInfo property)
                                            item_display = property.GetValue(item);
                                    }
                                }
                                e.DisplayText = (!string.IsNullOrEmpty(this.DisplayMember) ? item_display : item_value).ToString();
                                return;
                            }
                        }
                    }
                }
                else if (e.Value is Component component)
                {
                    e.DisplayText = component.Site.Name;
                }
                else if (e.Value.GetType().Attributes == TypeAttributes.Class)
                {
                    e.DisplayText = e.Value.GetType().Name;
                }
                else if (e.Value is Enum)
                {
                    Enum value = (Enum)e.Value;
                    var field = value.GetType().GetField(value.ToString());
                    var attribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false); // 获取描述属性
                    if (attribute.Length > 0)
                    {
                        DescriptionAttribute DescriptionAttribute = (DescriptionAttribute)attribute[0];
                        e.DisplayText = DescriptionAttribute.Description;
                    }
                }
            }
        }

        private bool EqualsValue(object value1, object value2)
        {
            if (value1 is int && value2 is long || value1 is long && value2 is int)
            {
                return value1 == value2;
            }
            else if (value1 is float && value2 is double || value1 is float && value2 is double)
            {
                return value1 == value2;
            }
            else if (value1 is float && value2 is decimal || value1 is float && value2 is decimal)
            {
                return value1 == value2;
            }
            else if (value1 is double && value2 is decimal || value1 is double && value2 is decimal)
            {
                return value1 == value2;
            }
            return false;
        }

        private void m_BaseEdit_KeyDown(object sender, KeyEventArgs e)
        {
            if (this.TextEditStyle == TextEditStyles.DisableTextEditor)
            {
                if (e.KeyCode == Keys.Delete || e.KeyCode == Keys.Back)
                {
                    this.SelectedValue = null;
                }
            }
            else if (this.TextEditStyle == TextEditStyles.Standard)
            {
                this._selectedValue = null;
            }
        }

        private void deleteButton_Click(object sender, EventArgs e)
        {
            this.Value = null;
        }
    }
}